﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using CMD_DKT.BAL;
using System.Threading;
using System.IO;
using RestSharp;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Controls;

namespace CMD_DKT.Synchronization
{
    class Sync
    {

        public static Thread t = null;

        public static Storyboard sb;

        public static bool CheckIsAlive()
        {

            if (Sync.t != null)
            {
                return Sync.t.IsAlive;

            }
            return false;

        }/////////

        public static void start(Storyboard board, MainWindow mw)
        {
            try
            {
                //sb = board;
                //sb.Begin(mw);
                
                if (!Sync.CheckIsAlive())
                {

                    Sync.t = new Thread(() =>
                    {
                        Action b = () => ((Storyboard)mw.FindResource("rotateImg")).Begin(mw, true);
                            Application.Current.Dispatcher.BeginInvoke(b, System.Windows.Threading.DispatcherPriority.Background);

                        Sync.SyncSol();

                        Thread.Sleep(3000);
                                                
                        Action a = () => ((Storyboard)mw.FindResource("rotateImg")).Stop(mw);
                        Application.Current.Dispatcher.BeginInvoke(a, System.Windows.Threading.DispatcherPriority.Background);

                        if (mw.Despliega1 != null)
                        {
                            Action c = () => mw.Despliega1.RefreshContadores();
                            Application.Current.Dispatcher.BeginInvoke(c, System.Windows.Threading.DispatcherPriority.Background);
                        }
                    });

                    Sync.t.IsBackground = true;


                    Sync.t.Start();

                }

            }
            catch (Exception ex)
            {
                throw ex;

            }

            //return solicitud;

        }/////////

        #region sync Files  ---------------------------------------------

        public static void SyncSol()
        {
            string msg = "";
            long sol;
            long unid_documentos;
            DataTable dtSolNotSync = new DataTable();
            DataTable dtDocsList;

            Bitacora log = new Bitacora();

            try
            {
                log.GuardaMensaje("--------------------- SINCRONIZACIÓN INICIADA --------------------", "SYNC");

                log.GuardaMensaje("- Obtener lista de solicitudes enviadas...", "SYNC");
                //obtener lista de solicitudes enviadas
                dtSolNotSync = Solicitud.GetSolToSyncFiles();   // status = enviado


                log.GuardaMensaje("- Obtener lista de solicitudes no sincronizadas...", "SYNC");
                //obtener lista de no sincronizadas
                DataRow[] notSync = dtSolNotSync.Select("UNID_SINC_STS_SOL IS NULL ");  // UNID_SINC_STS_SOL = null

                if (notSync.Length ==0)
                    log.GuardaMensaje("- No existen documentos para sincronizar.", "SYNC");

                foreach (DataRow row in notSync)
                {
                    bool parsed = long.TryParse(row["UNID_SOLICITUD"].ToString(), out sol);

                    if (parsed)
                    {
                        log.GuardaMensaje("-- INICIA sincronización de documentos para" + sol.ToString(), "SYNC");

                        // Obtener lista de documentos no subidos al servidor
                        //dtDocsList = CargarArchivos.GetArchivos(sol);
                        dtDocsList = Solicitud.GetDataToInsertSolDoc(sol);
                        DataRow[] notUploaded = dtDocsList.Select("doctos_sync <> 1");      //("doctos_uploaded <> 1");             // UPLOADED != 1

                        int count = 0;
                        foreach (DataRow doc in notUploaded)
                        {
                            // copiado de archivos por cada solicitud
                            if (UploadFiles(doc,log))
                                count++;
                        }//foreach

                        if (count > 0)
                        {
                            unid_documentos = long.Parse(dtDocsList.Rows[0]["doctos_unidDoctos"].ToString());

                            log.GuardaMensaje("-- actualizar UNID_SINC_STS_DOCS con la llave de documentos resultante ", "SYNC");

                            // actualizar UNID_SINC_STS_DOCS con la llave de documentos resultante 
                            Solicitud.InsertSolSyncDoc(sol, unid_documentos);
                        }
                        log.GuardaMensaje("-- FINALIZA sincronización de documentos para " + sol.ToString(), "SYNC");

                    }
                        
                }//foreach


                //sync solicitudes
                SyncData(log);//,sb,br);

                log.GuardaMensaje("--------------------- SINCRONIZACIÓN FINALIZADA --------------------", "SYNC");
                log.InserStackMessage();
                    
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                log.InserStackMessage();
            }

        }//end 

        private static void SyncData(Bitacora log)//, System.Windows.Media.Animation.Storyboard sb, System.Windows.Controls.Border br)
        {
            DataTable dtUploadedDocs = new DataTable();
            DataTable dtSolAllData = new DataTable();

            Dictionary<string, string> respuesta = new Dictionary<string, string>();
            long unid_sol;
            int affected = 0;


            string[] arr = AppConfs.ParamsNotIncludeGetSol.Split(',');

            try
            {
                log.GuardaMensaje("-- INICIA sincronización de datos de solicitudes", "SYNC");

                log.GuardaMensaje("--- Listar las solicitudes las cuales ya han sincronizado sus documentos... ", "SYNC");

                // 1. Listar las solicitudes las cuales ya han sincronizado sus documentos
                dtUploadedDocs = Solicitud.GetSolUploadedDocs();

                if (dtUploadedDocs.Rows.Count >0)
                    log.GuardaMensaje("--- Obtener datos de cada una de esas solicitudes... ", "SYNC");
                else log.GuardaMensaje("--- No hay solicitudes con documentos sincronizados. ", "SYNC"); 

                // 2. Obtener todos los datos de cada una de esas solicitudes
                for (int a = 0; a < dtUploadedDocs.Rows.Count; a++)
                {
                    dtSolAllData = Solicitud.GetSolAllData(long.Parse(dtUploadedDocs.Rows[a]["UNID_SOLICITUD"].ToString()));

                    if (dtSolAllData.Rows.Count ==0)
                        log.GuardaMensaje("--- La solicitud " + dtUploadedDocs.Rows[a]["UNID_SOLICITUD"].ToString() 
                            + " no está lista para ser sincronizada.", "SYNC");

                    // 3. insertar la lista anterior de registros el servidor
                    for (int i = 0; i < dtSolAllData.Rows.Count; i++)
                    {
                        Dictionary<string, string> parametros = new Dictionary<string, string>();
                        for (int j = 0; j < dtSolAllData.Columns.Count; j++)
                        {
                            // se crea el diccionario con los valores del rengón para mandarlo a serializar
                            //if (dtSolAllData.Columns[j].ColumnName == "datsol_isOtrosClientes" || dtSolAllData.Columns[j].ColumnName == "datsol_isProveedor"
                            //    || dtSolAllData.Columns[j].ColumnName == "datsol_isMismoDomicilio" || dtSolAllData.Columns[j].ColumnName == "datsol_isOtrasCategorias")
                            //    parametros.Add(dtSolAllData.Columns[j].ColumnName, Convert.ToInt32(dtSolAllData.Rows[i][j]).ToString());
                            //else
                            //{
                                switch(dtSolAllData.Columns[j].ColumnName)
                                {
                                    case "sol_idSolStat":
                                        parametros.Add(dtSolAllData.Columns[j].ColumnName, "3");
                                        break;
                                    case "datsol_isOtrosClientes":
                                        parametros.Add(dtSolAllData.Columns[j].ColumnName, Convert.ToInt32(dtSolAllData.Rows[i][j]).ToString());
                                        break;
                                    case "datsol_isProveedor":
                                        parametros.Add(dtSolAllData.Columns[j].ColumnName, Convert.ToInt32(dtSolAllData.Rows[i][j]).ToString());
                                        break;
                                    case "datsol_isMismoDomicilio":
                                        parametros.Add(dtSolAllData.Columns[j].ColumnName, Convert.ToInt32(dtSolAllData.Rows[i][j]).ToString());
                                        break;
                                    case "datsol_isOtrasCategorias":
                                        parametros.Add(dtSolAllData.Columns[j].ColumnName, Convert.ToInt32(dtSolAllData.Rows[i][j]).ToString());
                                        break;
                                    default:
                                        parametros.Add(dtSolAllData.Columns[j].ColumnName, dtSolAllData.Rows[i][j].ToString());
                                        break;
                                }
                            //}
                        }//for

                        foreach (string item in arr)
                        {
                            parametros.Remove(item);
                        }

                        string param = Solicitud.SerializeParamWCFService(parametros); // se serializa el renglón

                        log.GuardaMensaje("--- Llamada al servicio WCF. InsertSolicitudWeb: "+param, "SYNC");

                        try
                        {
                            // llamar al servicio web que debe utilizar el SP de UPSERT DE SOLICITUD pero del lado del servidor
                            respuesta = CallWCFService2(AppConfs.WCFService, "InsertSolicitudWeb", param);
                        
                            if (respuesta.ContainsKey("InsertSolicitudWebResult"))
                            {
                                bool x = long.TryParse(respuesta["InsertSolicitudWebResult"], out unid_sol);
                                if (x && unid_sol > 0)
                                {
                                    log.GuardaMensaje("---  Se actualiza el status de la solicitud a \"en proceso\" y UNID_SINC_STS_SOL= UNID devuelto por el servicio.", "SYNC");
                                    // Se actualiza el status de la solicitud a "en proceso" y UNID_SINC_STS_SOL= UNID devuelto por el servicio
                                    affected = Solicitud.InsertSolSyncSol(long.Parse(dtUploadedDocs.Rows[a]["UNID_SOLICITUD"].ToString()), unid_sol, AppConfs.Status_proceso);
                                    if (dtSolAllData.Rows[i]["sol_idTipoSol"].ToString() == "2")
                                        EnviarSAP(dtUploadedDocs.Rows[a]["UNID_SOLICITUD"].ToString(), log);
                                }
                                else
                                {
                                    log.GuardaMensaje("--- No se insertó la solicitud. La respuesta del servicio fué: " + respuesta["InsertSolicitudWebResult"], "SYNC");
                                }

                            }//if
                        }
                        catch (Exception ex)
                        {
                            log.GuardaMensaje("--- Excepción en SyncData: " + ex.Message, "SYNC");
                                
                        }
                    }//for rows
                }//for rows

                log.GuardaMensaje("-- FINALIZA sincronización de datos de solicitudes", "SYNC");


            }
            catch (Exception ex)
            {

                string mensaje = ex.Message.Replace("\'", "\"");
                log.GuardaMensaje("-- No se pudo completar la sincronización. EXCEPCIÓN LANZADA EN EL MÉTODO SyncData:" + @mensaje, "SYNC");
                throw ex;
            }


        }

        private static void EnviarSAP(string p,Bitacora log)
        {
            string mensaje = "";
            try
            {
                Dictionary<string, string> parametros = new Dictionary<string, string>();
                Dictionary<string, Dictionary<string, string>> enviar = new Dictionary<string, Dictionary<string, string>>();
                DataTable dt = Solicitud.GetSapSap(p);
                if (dt.Rows.Count == 0)
                {
                    log.GuardaMensaje("La solicitud ["+p+"] no tiene parametros de mensaje", "SAP");
                    return;
                }
                else
                {
                    for (int i = 0; i < dt.Columns.Count; i++)
                    {
                        if (!System.DBNull.Value.Equals(dt.Rows[0][i]))
                            parametros.Add(dt.Columns[i].ColumnName.ToString(), dt.Rows[0][i].ToString());
                    }
                    enviar.Add( "SAP",parametros);
                }
                dt = Solicitud.GetMensajeSap(p);
                parametros = new Dictionary<string, string>();
                if (dt.Rows.Count == 0)
                {
                    log.GuardaMensaje("La solicitud [" + p + "] no tiene parametros de Sap", "SAP");
                    //return;
                }
                else
                {
                    for (int i = 0; i < dt.Columns.Count; i++)
                    {
                        if (!System.DBNull.Value.Equals(dt.Rows[0][i]))
                            parametros.Add(dt.Columns[i].ColumnName.ToString(), dt.Rows[0][i].ToString());
                    }
                    enviar.Add("mensajeSAP", parametros);
                }
                string json2 = Solicitud.SerializeParamWCFService(enviar);
                Solicitud.CallWCFService(AppConfs.WCFService, "ServicioSap", new { DatosSap = json2 });
                log.GuardaMensaje("Mensaje de Sap enviado exitosamente","SAP");
                return;
            }
            catch (Exception ex)
            {
                log.GuardaMensaje("Ocurrio un error al tratar de enviar los parametros de Sap: "+ex.Message, "SAP");
                return;
            }
        }//DocsLogUpdate

        private static bool UploadFiles(DataRow docRow, Bitacora log)
        {
            Dictionary<string, string> registroDoc = new Dictionary<string, string>();
            bool done = false;
            string[] access = Utilities.Utilities.CheckPathAccess(AppConfs.ServerDocsFolder,false);

            if (Directory.Exists(AppConfs.ServerDocsFolder) && access[0] =="1")
            {
                try
                {
                    log.GuardaMensaje("--- INICIA copiado de archivos a carpeta compartida...", "SYNC");

                    File.Copy(AppConfs.ClientDocsFolder + docRow["doctos_genFile"].ToString(), AppConfs.ServerDocsFolder + docRow["doctos_genFile"].ToString(), true);    //copia a la carpeta compartida

                    log.GuardaMensaje("--- Marcar documento " + docRow["doctos_genFile"].ToString() + " como enviado", "SYNC");
                    // Marcar el documento como enviado
                    int rAffected = Solicitud.SetDocUploadedFlag(docRow["doctos_unidDoc"].ToString());

                    if (rAffected > 0)
                        docRow["doctos_uploaded"] = 1;

                    //SerializeParamWCFService
                    for (int i = 0; i < docRow.Table.Columns.Count; i++)
                    {
                        //if (docRow.Table.Columns[i].ColumnName == "doctos_uploaded")
                        //    registroDoc.Add(docRow.Table.Columns[i].ColumnName, Convert.ToInt32(docRow[i]).ToString());
                        //else
                        switch (docRow.Table.Columns[i].ColumnName)
                        {
                            case "doctos_uploaded":
                                registroDoc.Add(docRow.Table.Columns[i].ColumnName, Convert.ToInt32(docRow[i]).ToString());
                                break;
                            default:
                                registroDoc.Add(docRow.Table.Columns[i].ColumnName, docRow[i].ToString());
                                break;
                        }
                    }


                    // usar servicio web, pasarle como parámetro: registroDoc
                    // Insertar en el servidor el registro del documento enviado... SP_CMD_INSERT_SOL_DOCS
                    string paramSerial = Solicitud.SerializeParamWCFService(registroDoc);

                    log.GuardaMensaje("--- Llamada al Servicio WCF. InsertDocs:  " + paramSerial, "SYNC");

                    Dictionary<string, string> respuesta = CallWCFService(AppConfs.WCFService, "InsertDocs", paramSerial);

                    long unid_doc;
                    // 4. tomar el UNID que devolvió el servicio e insertatrlo en el LOG de documentos del cliente
                    if (respuesta.ContainsKey("InsertDocsResult"))
                    {
                        string[] arr = respuesta["InsertDocsResult"].Split(',');

                        //bool a = long.TryParse(respuesta["InsertDocsResult"], out unid_doc);
                        bool a = long.TryParse(arr[1].Split(':')[1], out unid_doc);
                        if (a && unid_doc > 0)
                        {
                            log.GuardaMensaje("--- Insertar UNID " + unid_doc.ToString() + " en el Log de documentos.", "SYNC");

                            Solicitud.InsertInServer_SolDocs(unid_doc, "", ""); //long.Parse(row["doctos_unidDoc"].ToString())

                            log.GuardaMensaje("--- actualizar el valor SYNCHRONIZED en la tabla CMD_SOLICITUD_DOC ", "SYNC");

                            // 5. actualizar el valor SYNCHRONIZED en la tabla CMD_SOLICITUD_DOC
                            int affected = Solicitud.SetDocSyncFlag(unid_doc);   //long.Parse(row["doctos_unidDoc"].ToString())
                            if (affected > 0)
                                done = true;
                        }//if
                    }
                    else if (respuesta.ContainsKey("Exception"))
                    {
                        log.GuardaMensaje("--- Excepción devuelta por el servicio web para el unidDoc: " + docRow["doctos_unidDoc"].ToString() + " => " + respuesta["Exception"], "SYNC");
                    }
                    else if (respuesta.ContainsKey("ERROR"))
                    {
                        log.GuardaMensaje("--- Error devuelto por el servicio web para el unidDoc: " + docRow["doctos_unidDoc"].ToString() + " => " + respuesta["ERROR"], "SYNC");
                    }

                    log.GuardaMensaje("--- FINALIZA copiado de archivo  al servidor.", "SYNC");
                }
                catch (Exception ex)
                {
                    string mensaje = ex.Message.Replace("\'", "\"");
                    log.GuardaMensaje("-- No se pudo completar la sincronización. EXCEPCIÓN LANZADA EN EL MÉTODO UploadFiles:" + @mensaje, "SYNC");
                    throw ex;
                }

            }//if
            else {
                log.GuardaMensaje("--- No se countinúa con copiado de documentos: "+access[1], "SYNC");
            }

            return done;

        }//end UploadFiles

        private static Dictionary<string, string> CallWCFService(string service, string resource, string parametros)
        {
            Dictionary<string, string> res;

            try
            {
                var client = new RestClient(service);
                client.Authenticator = new HttpBasicAuthenticator("administrator", "Passw0rd1!");//new SimpleAuthenticator("username", "win-65ate595ire\\administrator", "password", "Passw0rd1!");
                //client.Authenticator = new NtlmAuthenticator();

                //new HttpBasicAuthenticator("win-65ate595ire\\administrator", "Passw0rd1!");

                var request = new RestRequest(Method.POST);
                request.Resource = resource;
                request.RequestFormat = RestSharp.DataFormat.Json;

                request.AddHeader("Content-type", "application/json");

                request.AddBody(new { parametrosDocs = parametros });
                //request.AddParameter("parametrosDocs",parametros);

                IRestResponse response = client.Execute(request);

                try
                {
                    if (response.ErrorException == null)
                        res = Solicitud.DeserializeResponseWCFServide(response.Content);
                    else {
                        res = new Dictionary<string, string>();
                        res.Add("ERROR", response.ErrorException.Message);
                    }
                }
                catch (Exception ex) 
                {
                    res = new Dictionary<string, string>();
                    res.Add("Exception", ex.Message);
                }

                return res;
            }
            catch (Exception ex)
            {

                throw ex;
            }
        }

        private static Dictionary<string, string> CallWCFService2(string service, string resource, string parametros)
        {

            try
            {
                var client = new RestClient(service);
                //client.Authenticator = new HttpBasicAuthenticator("administrator", "Passw0rd1!");//new SimpleAuthenticator("username", "win-65ate595ire\\administrator", "password", "Passw0rd1!");
                client.Authenticator = new NtlmAuthenticator();

                //new HttpBasicAuthenticator("win-65ate595ire\\administrator", "Passw0rd1!");

                var request = new RestRequest(Method.POST);
                request.Resource = resource;
                request.RequestFormat = RestSharp.DataFormat.Json;

                request.AddHeader("Content-type", "application/json");

                request.AddBody(new { unidSolicitud = parametros }); //

                IRestResponse response = client.Execute(request);
                Dictionary<string, string> res = Solicitud.DeserializeResponseWCFServide(response.Content);

                return res;
            }
            catch (Exception ex)
            {

                throw ex;
            }
        }

        #endregion ---------------------------------------------------
        public static bool insertDataMasterRolWeb(long unidSolicitud)
        {
            DataTable dt;
            try
            {
                Dictionary<string, string> respuesta;
                dt = Solicitud.GetSolProceso(2);
                 var results = from DataRow myRow in dt.Rows
                              where myRow.Field<Int64>("UNID_SOLICITUD") == unidSolicitud
                              select myRow;
                DataTable dt1 = results.CopyToDataTable();
                respuesta=Solicitud.CallWCFService(AppConfs.WCFService, "InsertarSolWF", new { unidSolicitud = unidSolicitud ,
                                                                                     unidRol = dt1.Rows[0]["UNID_ROL"].ToString(),
                                                                                     status = dt1.Rows[0]["ID_SOLICITUD_STATUS"].ToString()});
                //if (respuesta.Keys.Contains())
                //    return false;
            //string unidSolicitud, string unidRol, string status, string fecha
                return true;
            }
            catch (Exception ex)
            {
                return false;

            }
            
        }
    }//end class

    
}
